﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Memcached.ClientLibrary;
using CSP.Common.CustomException;

namespace CSP.Common.CacheManage
{
    public class MemCachedProvider : ICacheProvider
    {
        private MemcachedClient client;

        public MemCachedProvider()
        {
            client = new MemcachedClient();
        }

        /// <summary>
        /// 获取缓存对象
        /// </summary>
        /// <typeparam name="T">任意的对象类型</typeparam>
        /// <param name="key">根据Key值查找对象</param>
        /// <returns></returns>
        public T GetData<T>(string key)
        {
            ExceptionFactory.StringNullorEmptyException(key);

            string depend_key = CacheKeys.DEPEND + key;
            object dependObj = client.Get(depend_key);
            if (dependObj != null && !IsEffectiveDependCache((MemCacheDependency[])dependObj))
            {
                return default(T);
            }

            object result = client.Get(key);
            if (result == null)
            {
                return default(T);
            }
            return (T)result;
        }

        /// <summary>
        /// 判断缓存对象是否存在
        /// </summary>
        /// <param name="key">根据Key值查找对象</param>
        /// <returns></returns>
        public bool IsExists(string key)
        {
            ExceptionFactory.StringNullorEmptyException(key);

            return client.KeyExists(key);
        }

        /// <summary>
        /// 添加缓存对象,如果存在将替换
        /// </summary>
        /// <typeparam name="T">任意的对象类型</typeparam>
        /// <param name="key">指定存储的key</param>
        /// <param name="value">指定存储的对象</param>
        /// <returns></returns>
        public bool AddData(string key, object value)
        {
            ExceptionFactory.StringNullorEmptyException(key);

            if (value == null)
            {
                return false;
            }

            if (IsExists(key))
            {
                return client.Set(key, value);
            }
            else
            {
                return client.Add(key, value);
            }

        }

        /// <summary>
        /// 添加缓存对象,如果存在将替换
        /// </summary>
        /// <typeparam name="T">任意的对象类型</typeparam>
        /// <param name="key">指定存储的key</param>
        /// <param name="value">指定存储的对象</param>
        /// <param name="absoluteExpiration">所添加对象将到期并被从缓存中移除的时间。</param>
        /// <param name="dependenceKeys">依赖的缓存键</param>
        /// <returns></returns>
        public bool AddData(string key, object value, DateTime absoluteExpiration, string[] dependenceKeys = null)
        {
            ExceptionFactory.StringNullorEmptyException(key);
            if (value == null)
            {
                return false;
            }

            if (dependenceKeys != null && dependenceKeys.Length > 0)
            {
                string depend_key = CacheKeys.DEPEND + key;
                //生成依赖缓存集合
                MemCacheDependency[] memCacheDependencys = GetDependCache(dependenceKeys);

                //如果依赖项存在
                if (IsExists(depend_key))
                {
                    client.Set(depend_key, value, absoluteExpiration);
                }
                else
                {
                    return client.Add(depend_key, value, absoluteExpiration);
                }

            }

            if (IsExists(key))
            {
                return client.Set(key, value, absoluteExpiration);
            }
            else
            {
                return client.Add(key, value, absoluteExpiration);
            }
        }

        /// <summary>
        /// 添加缓存对象,如果存在将替换
        /// </summary>
        /// <typeparam name="T">任意的对象类型</typeparam>
        /// <param name="key">指定存储的key</param>
        /// <param name="value">指定存储的对象</param>
        /// <param name="slidingExpiration">最后一次访问所添加对象时与该对象到期时之间的时间间隔</param>
        /// <param name="dependenceKeys">依赖的缓存键</param>
        /// <returns></returns>
        public bool AddData(string key, object value, TimeSpan slidingExpiration, string[] dependenceKeys = null)
        {
            DateTime absoluteExpiration = DateTime.Now.Add(slidingExpiration);
            return this.AddData(key, value, absoluteExpiration, dependenceKeys);
        }

        /// <summary>
        /// 删除缓存对象
        /// </summary>
        /// <param name="key">指定对象的key值</param>
        /// <returns></returns>
        public bool Remove(string key)
        {
            ExceptionFactory.StringNullorEmptyException(key);

            return client.Delete(key);
        }

        /// <summary>
        /// 获取依赖项
        /// </summary>
        /// <param name="dependenceKeys">所依赖的Cachekey</param>
        /// <returns></returns>
        private MemCacheDependency[] GetDependCache(string[] dependenceKeys)
        {
            if (dependenceKeys == null || dependenceKeys.Length == 0)
            {
                throw new Exception("dependenceKeys Can't be null");
            }

            MemCacheDependency[] memCacheDependencys = new MemCacheDependency[dependenceKeys.Length];
            for (int i = 0; i < dependenceKeys.Length; i++)
            {
                memCacheDependencys[i] = new MemCacheDependency(dependenceKeys[i]);
            }
            return memCacheDependencys;
        }

        /// <summary>
        /// 判断依赖项是否有效
        /// </summary>
        /// <param name="memCacheDependencys">,默认空依赖项，则表示有效</param>
        /// <returns></returns>
        private bool IsEffectiveDependCache(MemCacheDependency[] memCacheDependencys)
        {
            if (memCacheDependencys == null || memCacheDependencys.Length == 0)
            {
                return true;
            }
            for (int i = 0; i < memCacheDependencys.Length; i++)
            {
                bool isExists = client.KeyExists(memCacheDependencys[i].Dependkey);

                if (!isExists)
                {
                    return false;
                }
            }

            return true;
        }
    }
}
